package cn.haohaowo.spring.chapter5;


import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import junit.framework.Assert;

import org.junit.Test;
import org.springframework.context.expression.BeanFactoryAccessor;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;


public class SpELTest {

//	@Test
	public void helloWorld() {
		ExpressionParser parser = new SpelExpressionParser();
		Expression expression = parser.parseExpression("('Hello' + ' World').concat(#end)");
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("end", "!");
		Assert.assertEquals("Hello World!", expression.getValue(context));
	}
	
//	@Test
	public void testParserContext() {
		ExpressionParser parser = new SpelExpressionParser();
		ParserContext parserContext = new ParserContext() {
			
			@Override
			public boolean isTemplate() {
				return true;
			}
			
			@Override
			public String getExpressionSuffix() {
				return "}";
			}
			
			@Override
			public String getExpressionPrefix() {
				return "#{";
			}
		};
		String template = "#{'Hello '}#{'World'}";
		Expression expression = parser.parseExpression(template, parserContext);
		Assert.assertEquals("Hello World", expression.getValue());
	}
	
//	@Test
	public void testClassTypeExpression() {
		ExpressionParser parser = new SpelExpressionParser();
		Class<String> result1 = parser.parseExpression("T(String)").getValue(Class.class);
		Assert.assertEquals(String.class, result1);
		
		String expression2 = "T(cn.haohaowo.spring.chapter5.SpELTest)";
		Class<String> result2 = parser.parseExpression(expression2).getValue(Class.class);
		Assert.assertEquals(SpELTest.class, result2);
		
		int result3 = parser.parseExpression("T(Integer).MAX_VALUE").getValue(Integer.class);
		Assert.assertEquals(Integer.MAX_VALUE, result3);
		
		int result4 = parser.parseExpression("T(Integer).parseInt(1)").getValue(Integer.class);
		Assert.assertEquals(1, result4);
	}
	
//	@Test
	public void testConstructorExpression() {
		ExpressionParser parser = new SpelExpressionParser();
		String result1 = parser.parseExpression("new String('haha')").getValue(String.class);
		Assert.assertEquals("haha", result1);
		
		Date result2 = parser.parseExpression("new java.util.Date()").getValue(Date.class);
		Assert.assertNotNull(result2);
	}
	
//	@Test
	public void testVariableExpression() {
		ExpressionParser parser = new SpelExpressionParser();
		EvaluationContext context = new StandardEvaluationContext();
		context.setVariable("variable", "haha");
		context.setVariable("variable", "haha");
		String result = parser.parseExpression("#variable").getValue(context, String.class);
		Assert.assertEquals("haha", result);
		
		context = new StandardEvaluationContext("haha");
		String result2 = parser.parseExpression("#root").getValue(context, String.class);
		Assert.assertEquals("haha", result2);
		String result3 = parser.parseExpression("#this").getValue(context, String.class);
		Assert.assertEquals("haha", result3);
	}
	
//	@Test
	public void testFunctionExpression() throws SecurityException, NoSuchMethodException {
		ExpressionParser parser = new SpelExpressionParser();
		StandardEvaluationContext context = new StandardEvaluationContext();
		Method parseInt = Integer.class.getDeclaredMethod("parseInt", String.class);
		context.registerFunction("parseInt", parseInt);
		context.setVariable("parseInt2", parseInt);
		String expression1 = "#parseInt('3') == #parseInt2('3')";
		boolean result1 = parser.parseExpression(expression1).getValue(context, Boolean.class);
		Assert.assertEquals(true, result1);
	}
	
//	@Test
	public void testAssignExpression() {
		ExpressionParser parser = new SpelExpressionParser();
		EvaluationContext context = new StandardEvaluationContext("aaa");
		String result1 = parser.parseExpression("#root = 'aaa'").getValue(context, String.class);
		Assert.assertEquals("aaa", result1);
		String result2 = parser.parseExpression("#this = 'aaa'").getValue(context, String.class);
		Assert.assertEquals("aaa", result2);
		
		context.setVariable("#variable", "variable");
		String result3 = parser.parseExpression("#variable = #root").getValue(context, String.class);
		Assert.assertEquals("aaa", result3);
		
		Date date = new Date();
		StandardEvaluationContext context1 = new StandardEvaluationContext(date);
		int result4 = parser.parseExpression("Year").getValue(context1, Integer.class);
		Assert.assertEquals(date.getYear(), result4);
		
		int result5 = parser.parseExpression("year").getValue(context1, Integer.class);
		Assert.assertEquals(date.getYear(), result5);
		
		context1.setRootObject(null);
		Object result6 = parser.parseExpression("#root?.year").getValue(context1, Object.class);
		Assert.assertEquals(null, result6);
		
		context1.setRootObject(date);
		int result7 = parser.parseExpression("Year = 4").getValue(context1, Integer.class);
		Assert.assertEquals(4, result7);
		
		parser.parseExpression("Year").setValue(context1, 5);
		int result8 = parser.parseExpression("Year").getValue(context1, Integer.class);
		Assert.assertEquals(5, result8);
		
		int result9 = parser.parseExpression("getYear()").getValue(context1, Integer.class);
		Assert.assertEquals(date.getYear(), result9);
	}
	
	@Test
	public void testBeanExpression() {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();
		ctx.refresh();
		ExpressionParser parser = new SpelExpressionParser();
		StandardEvaluationContext context = new StandardEvaluationContext();
		context.setBeanResolver(new BeanFactoryResolver(ctx));
		Properties result = parser.parseExpression("@systemProperties").getValue(context, Properties.class);
		Assert.assertEquals(System.getProperties(), result);
		
		List<Integer> result2 = parser.parseExpression("{1, 2, 3}").getValue(List.class);
		Assert.assertEquals(new Integer(1), result2.get(0));
		try {
			result2.set(0, 2);
			Assert.fail();
		} catch(Exception e) {
			
		}
		
		String expression3 = "{{1 + 2, 2 + 3}, {3, 4 + 4}}";
		List<List<Integer>> result3 = parser.parseExpression(expression3).getValue(List.class);
		result3.get(0).set(0, 1);
		Assert.assertEquals(2, result3.size());
	}
	
}
